package cn.school.pay.service.impl;

import cn.school.common.constant.CommonConstant;
import cn.school.common.utils.RedisUtils;
import cn.school.pay.dao.PayOrderInfoDao;
import cn.school.pay.service.IPayCertificateService;
import cn.school.pay.service.PayOrderInfoService;
import cn.school.pay.vo.AliPayCommonConfig;
import cn.school.pay.vo.PayCallBackBean;
import cn.school.pay.vo.PayCertificateInfoVO;
import cn.school.pay.vo.PayOrderInfoVO;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.*;

@Service
@Slf4j
public class PayOrderInfoServiceImpl extends ServiceImpl<PayOrderInfoDao, PayOrderInfoVO> implements PayOrderInfoService {

    @Autowired
    private PayOrderInfoDao payOrderInfoDao;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IPayCertificateService iPayCertificateService;

    @Override
    public IPage<PayOrderInfoVO> findPayOrderPageList(PayOrderInfoVO vo) {
        int count =  payOrderInfoDao.findPayOrderPageListCount(vo);
        int startNum=(vo.getPageNum()-1)*vo.getPageSize();
        vo.setPageNum(startNum);
        List<PayOrderInfoVO> billExpensesList =  payOrderInfoDao.findPayOrderPageList(vo);
        IPage<PayOrderInfoVO> page = new Page<>();
        page.setTotal(count);
        page.setRecords(billExpensesList);
        return page;

    }

    @Override
    public int addPayOrderInfo(PayOrderInfoVO vo) {
        String code = String.valueOf(Math.round((Math.random()+1) * 1000));
        String orderNo = "BZ" + DateUtil.format(new Date(),"yyyyMMddHHmmssSSS") + code;
        vo.setOrderNo(orderNo);
        vo.setOrderStatus("1");
        vo.setCreateTime(new Date());
        return this.baseMapper.insert(vo);
    }

    @Override
    public int updatePayOrderInfoByOrderNo(PayOrderInfoVO vo) {
        LambdaQueryWrapper<PayOrderInfoVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PayOrderInfoVO::getOrderNo,vo.getOrderNo());
        vo.setPayTime(new Date());
        return this.baseMapper.update(vo,wrapper);
    }

    @Override
    public int deletePayOrderInfoById(Long id) {
        return this.baseMapper.deleteById(id);
    }


    @Override
    public Map<String, Object> createPayOrder(PayOrderInfoVO vo) throws AlipayApiException, UnsupportedEncodingException {
        Map<String,Object> resultMap = new HashMap<>();
        //创建订单
        addPayOrderInfo(vo);
        //添加订单缓存，超时关闭支付
        redisUtils.set(CommonConstant.PAY_TIME_OUT_KEY+vo.getOrderNo(),JSON.toJSONString(vo),CommonConstant.PAY_TIME_OUT_LONG);
        //生产支付凭证
        String body = getBody(vo);


        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("params",body);
        System.out.println(body);
        return paramsMap;
    }

    private String getBody(PayOrderInfoVO vo) throws AlipayApiException {



        AliPayCommonConfig configVO = new AliPayCommonConfig();
        //获得初始化的AlipayClient
        AlipayClient alipayClient = alipayAppClient();

        //订单信息

        //支付宝安全啊认证信息
        AlipayTradeAppPayRequest request =new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model =new AlipayTradeAppPayModel();

        model.setSubject("支付宝支付");
        model.setOutTradeNo(vo.getOrderNo());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(String.valueOf(vo.getAmount()));    //单位为yuan
        request.setBizModel(model);
        request.setProdCode("QUICK_MSECURITY_PAY");
        Map<String,String> biz_content = new HashMap<>();
        biz_content.put("body","缴纳学费");
        biz_content.put("subject","缴纳学费");
        biz_content.put("out_trade_no",vo.getOrderNo());
        biz_content.put("timeout_express","10m");
        biz_content.put("total_amount",String.valueOf(vo.getAmount()));
        biz_content.put("product_code","QUICK_MSECURITY_PAY");
        request.setBizContent(JSON.toJSONString(biz_content));
        request.setNotifyUrl(configVO.getNotifyUrl());
        String body="";
        //app证书支付要用sdkExecute
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);

        //提交数据至支付宝时请使用
        return  response.getBody();
    }

    /**
     * 支付宝签名
     * @param map
     * @return
     */
    public String signAllString(Map<String,Object> map){
        Set<Map.Entry<String, Object>> set = map.entrySet();
        int num=0;
        StringBuffer sb = new StringBuffer("");
        for (Map.Entry<String, Object> entry : set) {
            if(num==(set.size()-1)){
                sb.append(entry);
            }else{
                sb.append(entry+"&");
            }
            num++;
        }

        System.out.println(sb.toString());
        return sb.toString();
//        String sign = "";
//        try {
//            AliPayCommonConfig alipayConfig = new AliPayCommonConfig();
//
//            sign = URLEncoder.encode(RSA.sign(sb.toString(), alipayConfig.getMerchantPrivateKey(), "utf-8"), "utf-8");//private_key私钥
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
//        sb.append("&sign="+sign+"&");
//        sb.append("sign_type=RSA");
//        sb.append(sign);
//        return sign;
    }

    @Override
    public String aliNotifyCallbackPayOffline(Map<String, String> param) {
        log.info("aliNotifyCallbackPayOffline:{}",param);
        // 调用SDK验证签名
        String appid = String.valueOf(param.get("app_id"));
        //从缓存中取支付信息
        String alipayConfigJsonStr = redisUtils.get("AliPayConfig");
        if(StringUtils.isEmpty(alipayConfigJsonStr)){
            iPayCertificateService.refreshConfigCache();
            alipayConfigJsonStr = redisUtils.get("AliPayConfig");
        }
        PayCertificateInfoVO infoVO = JSON.parseObject(alipayConfigJsonStr,PayCertificateInfoVO.class);

        AliPayCommonConfig config = new AliPayCommonConfig();


        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.certVerifyV1(param,infoVO.getAlipayCertPath(),"UTF-8","RSA2");
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if (signVerified) {
            log.info("check pass");
            // 按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success，校验失败返回failure
            //this.check(param);
            String trade_status = String.valueOf(param.get("trade_status"));
            if (trade_status.equals("TRADE_SUCCESS") || trade_status.equals("TRADE_FINISHED")) {
                // 封装回调参数
                PayCallBackBean payCallBackBean = new PayCallBackBean();
                String outTradeNo = String.valueOf(param.get("trade_no"));// 支付宝交易号
                String orderNo = String.valueOf(param.get("out_trade_no")); // 平台交易号
                String total_amount = param.get("total_amount");//交易金额
                // 另起线程处理回调业务 TODO
                handleOrderInfo(outTradeNo, orderNo, total_amount);
            } else {
                log.info(" check no pass");
            }
            return "success";
        } else {
            return "failure";
        }
    }

    private void handleOrderInfo(String outTradeNo, String orderNo, String total_amount) {
        PayOrderInfoVO vo = new PayOrderInfoVO();
        LambdaQueryWrapper<PayOrderInfoVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PayOrderInfoVO::getOrderNo, orderNo);
        PayOrderInfoVO payOrderVO = this.baseMapper.selectOne(wrapper);
        //查询到用户信息，更新余额

        vo.setOrderStatus("3");
        vo.setPayTradeNo(outTradeNo);
        vo.setPayTime(new Date());
        //修改订单状态
        this.baseMapper.update(vo, wrapper);
        log.info("pay order status update end");
        //添加交易流水

        //更新用户余额

        log.info("update user balance end");
        //删除超时订单标识
        redisUtils.delete(CommonConstant.PAY_TIME_OUT_KEY+vo.getOrderNo());
    }

    public AlipayClient alipayAppClient(){
        AliPayCommonConfig configVO = new AliPayCommonConfig();
        String alipayConfigJsonStr = redisUtils.get("AliPayConfig");
        if(StringUtils.isEmpty(alipayConfigJsonStr)){
            iPayCertificateService.refreshConfigCache();
            alipayConfigJsonStr = redisUtils.get("AliPayConfig");
        }
        PayCertificateInfoVO infoVO = JSON.parseObject(alipayConfigJsonStr,PayCertificateInfoVO.class);

        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(configVO.getGatewayUrl());
        certAlipayRequest.setAppId(infoVO.getAlipayAppid());
        certAlipayRequest.setPrivateKey(infoVO.getAlipayPrivateKey());
        certAlipayRequest.setFormat("json");
        certAlipayRequest.setCharset(configVO.getCharset());
        certAlipayRequest.setSignType(configVO.getSignType());
        certAlipayRequest.setCertPath(infoVO.getAlipayAppCertPath());
        certAlipayRequest.setAlipayPublicCertPath(infoVO.getAlipayCertPath());
        certAlipayRequest.setRootCertPath(infoVO.getAlipayRootCertPath());
        try {
            AlipayClient client = new DefaultAlipayClient(certAlipayRequest);
            return client;
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws AlipayApiException {
        AliPayCommonConfig alipayConfig = new AliPayCommonConfig();

        String publicKey = AlipaySignature.getAlipayPublicKey("D:/cert/appCertPublicKey.crt");
        System.out.println("publicKey:"+publicKey);
    }
}
